package com.my.util;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.my.entity.SchedulerValue;
import com.my.service.SchedulerValueService;
import lombok.extern.slf4j.Slf4j;
import org.quartz.*;
import org.quartz.impl.JobDetailImpl;
import org.quartz.impl.StdSchedulerFactory;
import org.quartz.impl.matchers.GroupMatcher;
import org.quartz.impl.triggers.CronTriggerImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;

@Component("scheduleUtil")
@Slf4j
public class ScheduleUtil {

    private Scheduler scheduler;

    @Resource
    public ApplicationContext applicationContext;

    @Resource
    public SchedulerValueService svService;

    public ScheduleUtil() {
        try {
            scheduler = new StdSchedulerFactory().getScheduler();
        }catch (SchedulerException e) {
            e.printStackTrace();
        }
    }

    public static String getCron(Date date) {
        String dateFormat = "ss mm HH dd MM ? yyyy";

        SimpleDateFormat sdf = new SimpleDateFormat(dateFormat);
        String formatTimeStr = null;
        if (date != null) {
            formatTimeStr = sdf.format(date);
        }
        return formatTimeStr;
    }

    public void addJob(SchedulerValue schedule) throws ClassNotFoundException, IllegalAccessException, InstantiationException, SchedulerException, NoSuchMethodException {
        MethodInvokingJobDetailFactoryBean factoryBean = new MethodInvokingJobDetailFactoryBean();
        factoryBean.setConcurrent(false);
        factoryBean.setName(schedule.getJobName());
        Object targetBean = Class.forName(schedule.getClassName()).newInstance();
        factoryBean.setTargetObject(targetBean);
        factoryBean.setTargetMethod(schedule.getMethodName());
        if(StrUtil.isNotBlank(schedule.getRemark())) {
            factoryBean.setArguments(new JSONObject(schedule.getRemark()));
        }
        factoryBean.afterPropertiesSet();
        JobDetail detail = factoryBean.getObject();
        TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger();
        triggerBuilder.withIdentity(schedule.getTriggerName(), schedule.getTriggerGroupName());
        triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(schedule.isOnce() ? getCron(schedule.getStartTime()) : schedule.getCron()));
        if(schedule.getStartTime() == null) {
            triggerBuilder.startNow();
        }else {
            triggerBuilder.startAt(schedule.getStartTime());
        }
        if(schedule.getEndTime() != null) {
            triggerBuilder.endAt(schedule.getEndTime());
        }
        CronTrigger trigger = (CronTrigger) triggerBuilder.build();
        scheduler.scheduleJob(detail, trigger);
    }

    public void startJobAll() {
        try {
            if(scheduler.isStarted()) {
                System.out.println("定时器已启动！");
            }else {
                scheduler.start();
            }
        }catch (SchedulerException e) {
            e.printStackTrace();
        }
    }

    public void deleteJob(SchedulerValue value) {
        try {
            TriggerKey triggerKey = TriggerKey.triggerKey(value.getTriggerName(), value.getTriggerGroupName());
            scheduler.pauseTrigger(triggerKey);
            scheduler.unscheduleJob(triggerKey);
            scheduler.deleteJob(JobKey.jobKey(value.getJobName(), value.getTriggerGroupName()));
        }catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 修改定时任务时间
     * 不支持修改要执行的具体方法定时任务
     * @param SchedulerValue
     */
    public void modifyJobTime(SchedulerValue SchedulerValue) {
        try {
            TriggerKey triggerKey = TriggerKey.triggerKey(SchedulerValue.getTriggerName(), SchedulerValue.getTriggerGroupName());
            CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
            if (trigger == null) {
                return;
            }
            String oldTime = trigger.getCronExpression();
            if (!oldTime.equalsIgnoreCase(SchedulerValue.getCron())) {
                // 触发器
                TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder
                        .newTrigger();
                // 触发器名,触发器组
                triggerBuilder.withIdentity(SchedulerValue.getTriggerName(), SchedulerValue.getTriggerGroupName());
                triggerBuilder.startNow();
                // 触发器时间设定
                triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(SchedulerValue.getCron()));
                // 创建Trigger对象
                trigger = (CronTrigger) triggerBuilder.build();
                // 方式一 ：修改一个任务的触发时间
                scheduler.rescheduleJob(triggerKey, trigger);
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }



    /**
     * 指定更新
     */
    public void  replaceJob(SchedulerValue SchedulerValue) throws ClassNotFoundException, NoSuchMethodException, InstantiationException, SchedulerException, IllegalAccessException {
        //先删除在添加
        deleteJob(SchedulerValue);
        addJob(SchedulerValue);
    }

    /**
     * 全部更新
     *
     */
    public void replaceJobAll() throws SchedulerException {
        deleteJobAll();
//        initJobAll();
    }


    /**
     * 移出所有
     */
    public void deleteJobAll() throws SchedulerException {
        scheduler.clear();
    }

    /**
     * 立即执行单个(待编写)
     */

    /**
     * 关闭单个（待编写）
     */

    /**
     * 功能：关闭所有定时任务
     */
    public void shutdownJobs() {
        try {
            if (!scheduler.isShutdown()) {
                scheduler.shutdown();

            }
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }

    /**
     * 查看全部
     * @return
     */
    public List<SchedulerValue> getAllJobs() {
        List<SchedulerValue> SchedulerValueList = new ArrayList<>();
        try {
            //再获取Scheduler下的所有group
            List<String> triggerGroupNames = scheduler.getTriggerGroupNames();
            for (String groupName : triggerGroupNames) {
                //组装group的匹配，为了模糊获取所有的triggerKey或者jobKey
                GroupMatcher groupMatcher = GroupMatcher.groupEquals(groupName);
                //获取所有的triggerKey
                Set<TriggerKey> triggerKeySet = scheduler.getTriggerKeys(groupMatcher);
                for (TriggerKey triggerKey : triggerKeySet) {
                    //通过triggerKey在scheduler中获取trigger对象
                    CronTriggerImpl trigger = (CronTriggerImpl)scheduler.getTrigger(triggerKey);

                    //获取trigger拥有的Job
                    JobKey jobKey = trigger.getJobKey();
                    JobDetailImpl jobDetail = (JobDetailImpl) scheduler.getJobDetail(jobKey);
                    JobDataMap jobDataMap = jobDetail.getJobDataMap();
                    MethodInvokingJobDetailFactoryBean methodInvokingJobDetailFactoryBean = (MethodInvokingJobDetailFactoryBean)jobDataMap.get("methodInvoker");

                    //组装页面需要显示的数据
                    SchedulerValue SchedulerValue = new SchedulerValue();
                    SchedulerValue.setClassName(methodInvokingJobDetailFactoryBean.getTargetClass().getName());
                    SchedulerValue.setMethodName(methodInvokingJobDetailFactoryBean.getTargetMethod());
                    SchedulerValue.setStartTime(trigger.getStartTime());
                    SchedulerValue.setEndTime(trigger.getEndTime());
                    SchedulerValue.setTriggerGroupName(groupName);
                    SchedulerValue.setTriggerName( trigger.getName());
                    SchedulerValue.setJobName(jobDetail.getName());
                    SchedulerValue.setCron(trigger.getCronExpression());
                    SchedulerValue.setId(trigger.getTimeZone().getID());
                    SchedulerValueList.add(SchedulerValue);
                }
            }
        } catch (Exception e) {
            log.error("获取定时任务信息出错", e);
        }
        return SchedulerValueList;
    }

    /**
     * 初始化全部定时任务
     */
    @PostConstruct
    public void initJobAll(){
        List<SchedulerValue> list = svService.list();
        for(SchedulerValue schedulerValue : list) {
            try {
                addJob(schedulerValue);
            } catch (SchedulerException | NoSuchMethodException | ClassNotFoundException e) {
                e.printStackTrace();
                log.error(e.getMessage());
            } catch (IllegalAccessException | InstantiationException e) {
                e.printStackTrace();
            }
        }
        startJobAll();
    }

}
